//===========================================================================
// stops playback, removes current track's file in the recycle bin, and starts playback again (next track)
//===========================================================================

#include <windows.h>
#include <stdio.h>
#include <Psapi.h>
#include "..\helpers.h"
#include "..\wa_ipc.h"
#include "..\WINAMPCMD.H"

#define WINAMP_IS_STOPPED	0
#define WINAMP_IS_PLAYING	1
#define WINAMP_IS_PAUSED	3

const WCHAR szMutexname[]=L"winamp_DeleteAndNext";
const WCHAR szAppTitle[]=L"DeleteAndNext - WinampControlsApps";

WCHAR msg[1024];

enum playerTypes {ptUnknown, ptWinamp, ptAimp3};

void Beeeep();
void RemoveMissingItemsFromPlaylist(playerTypes player);

//==========================================================

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	// prevent occasional button double pressing
	HANDLE mutex;
	mutex=CreateMutex(NULL, TRUE, szMutexname);
	if(GetLastError()==ERROR_ALREADY_EXISTS){
		CloseHandle(mutex);
		Beeeep();
		return 1;		// program or rc-plugin is already running!
	}

	// search for Winamp main window
	HWND hwndWinAmp=FindWindow(L"Winamp v1.x", NULL);
	if(!hwndWinAmp)
		{
			MessageBeep(MB_ICONERROR);
			return 1;	// player is not running
		}

	// get current track playlist position
	int trackIndex = SendMessage(hwndWinAmp, WM_USER, 0, IPC_GETLISTPOS);
	// get address of the file name of the track
	int fileNamePtr = SendMessage(hwndWinAmp, WM_USER, trackIndex, IPC_GETPLAYLISTFILEW);
	
	const int fileNameSize = 2048;	// in bytes
	WCHAR fileName[fileNameSize/sizeof(WCHAR)];	// 1024 chars
	DWORD bytesWritten = 0;
	int i;

	DWORD pidWinamp;
	GetWindowThreadProcessId(hwndWinAmp, &pidWinamp);

	HANDLE phWinamp = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 1, pidWinamp);
	if(phWinamp == NULL)
	{
		MessageBeep(MB_ICONERROR);
		return 1;	// can't open process
	}

	// retrieve process filename
	WCHAR processImageFileName[1024];
	DWORD processImageFileNameSize=1024;

	QueryFullProcessImageName(phWinamp, 0, processImageFileName, &processImageFileNameSize);
	TrimString(processImageFileName);	// remove possible quotes
	WCHAR*imageFileName = wcsrchr(processImageFileName, '\\');
	imageFileName++;
	
	// determine what player we dealing with
	playerTypes playerType;
	if(wcsicmp(imageFileName, L"winamp.exe")==0)
		playerType=ptWinamp;
	else
		if(wcsicmp(imageFileName, L"aimp3.exe")==0)
			playerType=ptAimp3;
		else
			playerType=ptUnknown;

	// get current track filename
	ReadProcessMemory(phWinamp, (LPCVOID)fileNamePtr, fileName, fileNameSize, &bytesWritten);
	CloseHandle(phWinamp);
	
	// stop!
	SendMessage(hwndWinAmp, WM_COMMAND, WINAMP_BUTTON4, 0);
	
	// wait
	for(i=0; i<30; i++)	// wait for up to 30 seconds
	{
		if(SendMessage(hwndWinAmp, WM_WA_IPC, 0, IPC_ISPLAYING)==WINAMP_IS_STOPPED) break;
		Sleep(1000);
	}
	if(i==30)
	{
		swprintf(msg, L"Timeout while waiting for winamp stops.\n\n%s", fileName);

		#ifdef _DEBUG
			MessageBox(NULL, msg, (LPCWSTR)&szAppTitle, MB_ICONERROR);
		#else
			MessageBeep(MB_ICONERROR);
		#endif

		return 1;	// timeout
	}
	
	// delete
	if(IsFileExists(fileName))
	{
		// delete track to recycle bin
		SHFILEOPSTRUCT operation={0}; 
		operation.wFunc = FO_DELETE; 
		fileName[wcslen(fileName)+1]=0;	// .pFrom must be double-null terminated
		operation.pFrom = fileName;
		operation.fFlags = FOF_ALLOWUNDO|FOF_NO_UI|FOF_NORECURSION;
 
		int res;
		for(i=0; i<10; i++)	// SHFileOperation() can fail for a first time
		{
			// even files with Read only, Hidden and System attributes will be removed
			res=SHFileOperation(&operation);
			if(res==0) break;
			Sleep(1000);
		}
		if(i==10)
		{
			swprintf((wchar_t*)&msg, L"SHFileOperation() failed with error code 0x%x\n\n%s", res, fileName);

			#ifdef _DEBUG
				MessageBox(NULL, msg, (LPCWSTR)&szAppTitle, MB_ICONERROR);
			#else
				MessageBeep(MB_ICONERROR);
			#endif	
		}
	}
	else
		MessageBeep(MB_ICONERROR);

	// next track! (no need of this)
	//SendMessage(hwndWinAmp, WM_COMMAND, WINAMP_BUTTON5, 0);
	// play!
	SendMessage(hwndWinAmp, WM_COMMAND, WINAMP_BUTTON2, 0);

	RemoveMissingItemsFromPlaylist(playerType);

	// prevent occasional double button pressing
	Sleep(2000);
	CloseHandle(mutex);

	return 0;
}

//------------------------------------------

void Beeeep()
{
	const int delay = 50;
	Beep(1000, delay);
	Sleep(delay);
	Beep(1000, delay);
	Sleep(delay);
	Beep(1000, delay);
}

//------------------------------------------

void RemoveMissingItemsFromPlaylist(playerTypes player)
{
	HWND hwndWinampPlaylistEditor, hwndAimpPlaylistView;

	switch(player)
	{
	case ptWinamp:
		hwndWinampPlaylistEditor=FindWindow(L"BaseWindow_RootWnd", L"Main Window");
		hwndWinampPlaylistEditor=FindWindowEx(hwndWinampPlaylistEditor, NULL, L"BaseWindow_RootWnd", L"Playlist Editor");
		hwndWinampPlaylistEditor=FindWindowEx(hwndWinampPlaylistEditor, NULL, L"Winamp PE", L"Winamp Playlist Editor");
		PostMessage(hwndWinampPlaylistEditor, WM_COMMAND, 40222, 0); //it needs to go to the playlist window and not the main winamp window
		break;
	case ptAimp3:
		hwndAimpPlaylistView=FindWindow(L"TAIMP3MainWindow", NULL);
		hwndAimpPlaylistView=FindWindowEx(hwndAimpPlaylistView, NULL, L"TAIMPPlaylistDockForm", NULL);
		hwndAimpPlaylistView=FindWindowEx(hwndAimpPlaylistView, NULL, L"TAIMPPlaylistView", NULL);
		keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), 0, 0);
		Sleep(100);
		PostMessage(hwndAimpPlaylistView, WM_KEYDOWN, 0x45, 0);
		Sleep(100);
		keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_KEYUP, 0);
		break;
	}
}